﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.GUIEx.Usage;
using HK.Core.Utils;
using HK.Editor.BuildSystem;
using HK.Editor.Common;
using HK.Editor.GUIEx.Styles;
using UnityEditor;
using UnityEngine;
using HLogger = HK.Core.Logs.Logger;
using Object = UnityEngine.Object;

namespace HK.Editor.Utils
{
	/// <summary>
	/// 未知序列化Property类型异常
	/// </summary>
	public class UnknownPropertyProtoTypeException : Exception
	{
		public UnknownPropertyProtoTypeException(SerializedPropertyType iType, string iMessage) : 
			base($"{iMessage}(Type:{iType})") {}
	}
	
    /// <summary>
    /// GUI扩展
    /// </summary>
    public static class UtilsGUIEx
    {

#region Colors

		/// <summary>
		/// 选中颜色
		/// </summary>
		public static readonly Color SelectedColor = ColorEx.RoyalBlue0;

		/// <summary>
		/// 提示演示 - 一般
		/// </summary>
		public static readonly Color ColorNoticeGeneric = Color.clear;

		/// <summary>
		/// 提示演示 - 一般
		/// </summary>
		public static readonly Color ColorNoticeExecutable = Color.green;

		/// <summary>
		/// 提示演示 - 警告
		/// </summary>
		public static readonly Color ColorNoticeWarning = ColorEx.Golden0;

		/// <summary>
		/// 提示演示 - 错误
		/// </summary>
		public static readonly Color ColorNoticeError = ColorEx.FireBrick1;

		/// <summary>
		/// 可拖拽区域颜色
		/// </summary>
		public static readonly Color ColorDraggable = ColorEx.Chartreuse0;

		/// <summary>
		/// 可点击区域背景色
		/// </summary>
		public static readonly Color ColorClickable = ColorEx.Lycopene;

#endregion

#region Icons
        
		// 一般资源		
		public static readonly string BUILD_IN_ICON_RES_MAT = "d_Material Icon";
		public static readonly string BUILD_IN_ICON_RES_TEX = "textureExternal";
		public static readonly string BUILD_IN_ICON_RES_PREFAB = "d_Prefab Icon";
		public static readonly string BUILD_IN_ICON_RES_GO = "d_GameObject Icon";
#if UNITY_2019_4_40_OR_NEWER || UNITY_2020_2_OR_NEWER
	    public static readonly string BUILD_IN_ICON_RES_FOLDER = "d_FolderOpened Icon";
#else
	    public static readonly string BUILD_IN_ICON_RES_FOLDER = "d_OpenedFolder Icon";
#endif
		public static readonly string BUILD_IN_ICON_RES_SHADER = "d_Shader Icon";
		public static readonly string BUILD_IN_ICON_RES_MODEL = BUILD_IN_ICON_RES_PREFAB;
		public static readonly string BUILD_IN_ICON_RES_MESH = "d_MeshFilter Icon";
		public static readonly string BUILD_IN_ICON_RES_COLLIDER = "d_SphereCollider Icon";
		public static readonly string BUILD_IN_ICON_RES_LIGHT = "Main Light Gizmo";
		public static readonly string BUILD_IN_ICON_RES_PARTICLE = "d_ParticleSystem Icon";
		public static readonly string BUILD_IN_ICON_RES_SINGLE_PARTICLE = "ParticleSystem Gizmo";
		public static readonly string BUILD_IN_ICON_RES_SCENE = "d_SceneAsset Icon";
		
		// 提示类
		public static readonly string BUILD_IN_ICON_NOTICE_INFO = "d_console.infoicon";
		public static readonly string BUILD_IN_ICON_NOTICE_INFO_WARN = "d_console.warnicon";
		public static readonly string BUILD_IN_ICON_NOTICE_INFO_ERROR = "d_console.erroricon";
		public static readonly string BUILD_IN_ICON_NOTICE_HELP = "d__Help";
		public static readonly string BUILD_IN_ICON_NOTICE_VISIBLE = "d_ViewToolOrbit On";
		public static readonly string BUILD_IN_ICON_NOTICE_INVISIBLE = "d_ViewToolOrbit";
		public static readonly string BUILD_IN_ICON_NOTICE_SASSET = "d_ScriptableObject Icon";
		public static readonly string BUILD_IN_ICON_NOTICE_GENERIC = "EditorSettings Icon";
		
		// 操作类
		public static readonly string BUILD_IN_ICON_OPT_TOOLS = "d_CustomTool";
		public static readonly string BUILD_IN_ICON_OPT_SORT = "d_CustomSorting";
		public static readonly string BUILD_IN_ICON_OPT_DEL = "d_TreeEditor.Trash";
		public static readonly string BUILD_IN_ICON_OPT_LOCK = "IN LockButton on@2x";
		public static readonly string BUILD_IN_ICON_OPT_UNLOCK = "IN LockButton act@2x";
		public static readonly string BUILD_IN_ICON_OPT_PLAY = "d_PlayButton On";
		public static readonly string BUILD_IN_ICON_OPT_PLAY_PROFILE = "d_PlayButtonProfile On";
		public static readonly string BUILD_IN_ICON_OPT_FOLDOUT_OFF = "IN foldout act@2x";
		public static readonly string BUILD_IN_ICON_OPT_FOLDOUT_ON = "IN foldout focus on@2x";
		
		// 平台类
		public static readonly string BUILD_IN_ICON_PLATFORM_ANDROID = "d_BuildSettings.Android";
		public static readonly string BUILD_IN_ICON_PLATFORM_IOS = "d_BuildSettings.iPhone";
		public static readonly string BUILD_IN_ICON_PLATFORM_PS4 = "d_BuildSettings.PS4";
		public static readonly string BUILD_IN_ICON_PLATFORM_PS5 = "d_BuildSettings.PS5";
		public static readonly string BUILD_IN_ICON_PLATFORM_PS = BUILD_IN_ICON_PLATFORM_PS4;
		public static readonly string BUILD_IN_ICON_PLATFORM_PC = "d_BuildSettings.Standalone";
		public static readonly string BUILD_IN_ICON_PLATFORM_XBOX = "d_BuildSettings.PS5";
		public static readonly string BUILD_IN_ICON_PLATFORM_SWITCH = "d_BuildSettings.Switch";
		public static readonly string BUILD_IN_ICON_PLATFORM_WebGL = "d_BuildSettings.WebGL";

		private static readonly List<string> UnityBuildInIcons = new List<string>
		{
			// 一般资源类型
			BUILD_IN_ICON_RES_MAT,       BUILD_IN_ICON_RES_TEX,      BUILD_IN_ICON_RES_PREFAB,  BUILD_IN_ICON_RES_GO, 
			BUILD_IN_ICON_NOTICE_SASSET, BUILD_IN_ICON_RES_FOLDER,   BUILD_IN_ICON_RES_SHADER,  BUILD_IN_ICON_RES_MODEL,
			BUILD_IN_ICON_RES_MESH,      BUILD_IN_ICON_RES_COLLIDER, BUILD_IN_ICON_RES_LIGHT,   BUILD_IN_ICON_RES_SINGLE_PARTICLE,
			BUILD_IN_ICON_RES_PARTICLE,  BUILD_IN_ICON_RES_SCENE,
			
			// 提示类
			BUILD_IN_ICON_NOTICE_INFO,    BUILD_IN_ICON_NOTICE_INFO_WARN,  BUILD_IN_ICON_NOTICE_INFO_ERROR, BUILD_IN_ICON_NOTICE_HELP,
			BUILD_IN_ICON_NOTICE_VISIBLE, BUILD_IN_ICON_NOTICE_INVISIBLE,  BUILD_IN_ICON_NOTICE_GENERIC,
			
			// 操作类
			BUILD_IN_ICON_OPT_TOOLS,      BUILD_IN_ICON_OPT_SORT,  BUILD_IN_ICON_OPT_DEL,          BUILD_IN_ICON_OPT_LOCK,
			BUILD_IN_ICON_OPT_UNLOCK,     BUILD_IN_ICON_OPT_PLAY,  BUILD_IN_ICON_OPT_PLAY_PROFILE, BUILD_IN_ICON_OPT_FOLDOUT_OFF,
			BUILD_IN_ICON_OPT_FOLDOUT_ON,
			
			// 平台
			BUILD_IN_ICON_PLATFORM_ANDROID, BUILD_IN_ICON_PLATFORM_IOS,    BUILD_IN_ICON_PLATFORM_PS,      BUILD_IN_ICON_PLATFORM_PS4,     
			BUILD_IN_ICON_PLATFORM_PS5,     BUILD_IN_ICON_PLATFORM_PC,     BUILD_IN_ICON_PLATFORM_XBOX,    BUILD_IN_ICON_PLATFORM_SWITCH,
			BUILD_IN_ICON_PLATFORM_WebGL
		};
        
		/// <summary>
		/// 编辑器用Icon列表
		/// <para>* Key : Icon的AssetKey</para>
		/// <para>* Value : Icon纹理</para>
		/// </summary>
		private static Dictionary<string, Texture> _iconCaches = new Dictionary<string, Texture>();
		
		/// <summary>
		/// 生成Icon
		/// </summary>
		/// <param name="iAssetKey">Icon的AssetKey</param>
		/// <param name="iIconSize">Icon大小</param>
		/// <returns>Icon</returns>
		private static Texture GenerateIcon(string iAssetKey, int iIconSize = 16)
		{
			if (string.IsNullOrEmpty(iAssetKey)) return null;
			
			if (!_iconCaches.TryGetValue(iAssetKey, out var oIcon))
			{
				oIcon = LoadTextureFromFile(iAssetKey, iIconSize, iIconSize);
				_iconCaches.Add(iAssetKey, oIcon);
			}

			if (null == oIcon)
			{
				oIcon = LoadTextureFromFile(iAssetKey, iIconSize, iIconSize);
				_iconCaches[iAssetKey] = oIcon;
			}

			return oIcon;
		}

#endregion

#region Colors

		/// <summary>
		/// 取得GUI背景色
		/// </summary>
		/// <param name="iOptions">选项</param>
		/// <returns>GUI背景色</returns>
		private static Color GetGuiBgColor(int iOptions)
		{
			var clickable = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.Clickable);
			if (clickable)
			{
				return EditorConst.ColorClickable;
			}
			return Color.clear;
		}

#endregion

#region Content

		public static readonly GUIContent DefaultContent = new GUIContent("TestLabel");

		/// <summary>
		/// 创建GuiContent对象
		/// </summary>
		/// <param name="iLabel">文本</param>
		/// <param name="iIcon">Icon</param>
		/// <param name="iToolTips">属性Tips</param>
		/// <param name="iIconSize">Icon Size</param>
		/// <returns>GuiContent对象</returns>
		public static GUIContent CreateGuiContentWithIcon(string iLabel, string iIcon, string iToolTips = null, int iIconSize = 16)
		{
			if (!string.IsNullOrEmpty(iIcon) && UnityBuildInIcons.Exists(iIcon.Equals))
			{
				var content = EditorGUIUtility.IconContent(iIcon, iLabel);
				if (null != content)
				{
					content.text = iLabel;
					content.tooltip = iToolTips;
					return content;
				}
			}
			
			if (string.IsNullOrEmpty(iIcon))
			{
				return CreateGuiContent(iLabel, iToolTips);
			}	        
			
			var icon = GenerateIcon(iIcon, iIconSize);
			if (null == icon)
			{
				HLogger.Error($"UtilsGUIEx::CreateGuiContentWithIcon():The path of icon is invalid!(Icon Path:{iIcon})");
				return null;
			}
            
			return CreateGuiContentWithIcon(iLabel, icon, iToolTips);
		}
		
		/// <summary>
		/// 创建GuiContent对象
		/// </summary>
		/// <param name="iLabel">文本</param>
		/// <param name="iIcon">Icon</param>
		/// <param name="iToolTips">属性Tips</param>
		/// <returns>GuiContent对象</returns>
		public static GUIContent CreateGuiContentWithIcon(string iLabel, Texture iIcon, string iToolTips)
		{
			if (string.IsNullOrEmpty(iLabel))
			{
				return string.IsNullOrEmpty(iToolTips) ? 
					new GUIContent(iIcon) : 
					new GUIContent(iIcon, iToolTips);
			}
	        
			return string.IsNullOrEmpty(iToolTips) ? 
				new GUIContent(iLabel, iIcon) : 
				new GUIContent(iLabel, iIcon, iToolTips);
		}

		/// <summary>
		/// 创建GuiContent对象
		/// </summary>
		/// <returns>GuiContent对象</returns>
		public static GUIContent CreateGuiContent()
		{
			return CreateGuiContent(null, null);
		}
		
		/// <summary>
		/// 创建GuiContent对象
		/// </summary>
		/// <param name="iLabel">文本</param>
		/// <param name="iToolTips">属性Tips</param>
		/// <returns>GuiContent对象</returns>
		public static GUIContent CreateGuiContent(string iLabel, string iToolTips = null)
		{
			return CreateGuiContent(iLabel, iToolTips, !string.IsNullOrEmpty(iToolTips));
		}
		
		/// <summary>
		/// 创建GUI - Content
		/// </summary>
		/// <param name="iAssetPath">Asset路径</param>
		/// <param name="iToolTips">提示信息</param>
		/// <param name="iShowPath">是否显示完整路径</param>
		/// <param name="iIncludeExtension">是否包含文件后缀</param>
		/// <returns>目标对象的Content</returns>
		public static GUIContent CreateGuiContentByPathOfAsset(
			string iAssetPath, string iToolTips = null, bool iShowPath = false,
			bool iIncludeExtension = true)
		{
			if(string.IsNullOrEmpty(iAssetPath))
			{
				return GUIContent.none;
			}

			// 文件存在
			var assetPath = iAssetPath;
			if (File.Exists(assetPath))
			{
				if (!UtilsIo.IsAssetPath(assetPath, out var oAssetPath))
				{
					oAssetPath = assetPath;
				}

				var tips = string.IsNullOrEmpty(iToolTips) ? oAssetPath : iToolTips;
				assetPath = iShowPath ? oAssetPath : UtilsIo.GetFileName(oAssetPath, iIncludeExtension);
				return new GUIContent(assetPath, LoadAssetIcon(oAssetPath), tips);
			}
			
			// 若为目录
			if (Directory.Exists(iAssetPath))
			{
				if (!UtilsIo.IsAssetPath(assetPath, out var oAssetPath))
				{
					oAssetPath = assetPath;
				}
				
				var tips = string.IsNullOrEmpty(iToolTips) ? oAssetPath : iToolTips;
				assetPath = iShowPath ? oAssetPath : UtilsIo.GetFileName(oAssetPath, iIncludeExtension);
				return CreateGuiContentWithIcon(assetPath, EditorConst.IconFolder, tips);
			}
            
			// 文件不存在
			var tipsTmp = string.IsNullOrEmpty(iToolTips) ? assetPath : iToolTips;
			assetPath = iShowPath ? assetPath : UtilsIo.GetFileName(assetPath, iIncludeExtension);
			return new GUIContent(assetPath, tipsTmp);
		}
		
		/// <summary>
		/// 加载Asset Icon
		/// </summary>
		/// <param name="iAssetPath">Asset Path</param>
		/// <returns>Asset Icon</returns>
		private static Texture LoadAssetIcon(string iAssetPath)
		{
			if (!_iconCaches.TryGetValue(iAssetPath, out var oIcon))
			{
				oIcon = AssetDatabase.GetCachedIcon(iAssetPath);
				_iconCaches.Add(iAssetPath, oIcon);
			}

			if (null == oIcon)
			{
				oIcon = AssetDatabase.GetCachedIcon(iAssetPath);
				_iconCaches[iAssetPath] = oIcon;
			}

			return oIcon;
		}
		
		/// <summary>
		/// 创建Content
		/// </summary>
		/// <param name="iLabel">文本</param>
		/// <param name="iToolTips">属性Tips</param>
		/// <param name="iNoticeable">可提示</param>
		/// <returns>GuiContent对象</returns>
		public static GUIContent CreateGuiContent(string iLabel, string iToolTips, bool iNoticeable)
		{
			if (string.IsNullOrEmpty(iToolTips))
			{
				return string.IsNullOrEmpty(iLabel) ? new GUIContent() : new GUIContent(iLabel);
			}

			if (iNoticeable)
			{
				return new GUIContent(iLabel, GenerateIcon(EditorConst.IconNotice), iToolTips);
			}

			return new GUIContent(iLabel, iToolTips);
		}

		/// <summary>
		/// 创建Content
		/// </summary>
		/// <param name="iAssembly">程序集</param>
		/// <param name="iNameSpace">命名空间</param>
		/// <param name="iProperty">Property</param>
		/// <param name="iDefaultContext">默认内容</param>
		/// <typeparam name="TUsage">Usage类型</typeparam>
		/// <returns>GuiContent对象</returns>
		public static GUIContent CreateContentByUsage<TUsage>(
			string iAssembly, string iNameSpace, SerializedProperty iProperty,
			string iDefaultContext = null)
			where TUsage : GUIUsageAttribute
		{
			GUIContent caption = null;
			if (!string.IsNullOrEmpty(iAssembly) && !string.IsNullOrEmpty(iNameSpace) && null != iProperty)
			{
				var childType = System.Reflection.Assembly.Load(iAssembly).GetType($"{iNameSpace}.{iProperty.type}");
				if (null != childType)
				{
					var usageAttrs = childType.GetCustomAttributes(typeof(TUsage), true);
					if (0 < usageAttrs.Length)
					{
						var firstAttr = usageAttrs.First();
						if (firstAttr is TUsage elementAttr)
						{
							var captionTxt = elementAttr.Caption;
							var icon = elementAttr.Icon;
							var tips = elementAttr.Tips;
							var propertyKey = elementAttr.PropertyKey;
							
							if (!string.IsNullOrEmpty(propertyKey))
							{
								var keyProperty = iProperty.FindPropertyRelative(propertyKey);
								if (null != keyProperty && !string.IsNullOrEmpty(keyProperty.stringValue))
								{
									captionTxt = keyProperty.stringValue;
								}
							}
							caption = string.IsNullOrEmpty(icon) ? 
								CreateGuiContent(captionTxt, tips) : 
								CreateGuiContentWithIcon(captionTxt, icon, tips);
						}
					}
				}
			}
			else
			{
				caption = CreateGuiContent(string.IsNullOrEmpty(iDefaultContext) ? "Unknown" : iDefaultContext);
			}
			return caption;
		}

#endregion

#region Controls

		/// <summary>
		/// 生成控件Id
		/// </summary>
		/// <param name="iRect">矩形区域</param>
		/// <param name="iHashCode">控件Hash码</param>
		/// <returns>控件Id</returns>
		public static int GenerateControlId(Rect iRect, int iHashCode) => GUIUtility.GetControlID(iHashCode, FocusType.Keyboard, iRect);
		
		/// <summary>
		/// 生成拖拽控件Id
		/// </summary>
		/// <param name="iRect">矩形区域</param>
		/// <param name="iHashCode">控件Hash码</param>
		/// <returns>拖拽控件Id</returns>
		public static int GenerateDragControlId(Rect iRect, int iHashCode) => GUIUtility.GetControlID(iHashCode, FocusType.Passive, iRect);

#endregion

#region Texture

		/// <summary>
		/// 加载纹理
		/// <para>* 若纹理实际尺寸超过指定尺寸，则会被相应的撑开</para>
		/// </summary>
		/// <param name="iAssetKey">Icon的AssetKey</param>
		/// <param name="iWidth">Icon纹理宽度</param>
		/// <param name="iHeight">Icon纹理高度</param>
		/// <returns>预览Icon纹理</returns>
		public static Texture2D LoadTextureFromFile(string iAssetKey, int iWidth = -1, int iHeight = -1)
		{

#if !DLL_ICONS_LOAD
			if (!File.Exists(iAssetKey))
			{
				HLogger.Error($"UtilsGUIEx::LoadTextureFromFile():The file is not exist!(AssetKey:{iAssetKey})");
				return null;
			}
#endif

            //创建Texture
            var width = 32;
			if (0 < iWidth)
			{
				width = iWidth;
			}
			var height = 32;
			if (0 < iHeight)
			{
				height = iHeight;
			}

			Texture2D texture = null;
#if DLL_ICONS_LOAD
	        texture = UtilsDlls.LoadIcon(iAssetKey, width, height);
	        if (null != texture) return texture;
#endif
		            
			texture = new Texture2D(width, height);
			//创建文件读取流
			using (var fs = new FileStream(iAssetKey, FileMode.Open, FileAccess.Read))
			{
				fs.Seek(0, SeekOrigin.Begin);
				//创建文件长度缓冲区
				var bytes = new byte[fs.Length];
				//读取文件
				var readBytes = fs.Read(bytes, 0, (int)fs.Length);

				if (0 < readBytes)
				{
					texture.LoadImage(bytes);
					texture.name = fs.Name;
				}
				else
				{
					texture = null;
				}
			}

			return texture;
		}

#endregion
        
#region ProgressBar

        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iDisplayTxt">进度条内容</param>
        /// <param name="iValue">进度值</param>
        /// <param name="iMaxValue">最大值</param>
        /// <param name="iCostTime">耗时(单位:毫秒)</param>
        /// <para>百分比进度</para>
        public static float DisplayProgressBar(string iTitle, string iDisplayTxt, long iValue, long iMaxValue, long iCostTime = -1L)
        {
            if(CiMode.None != BuildParameters.CiMode) return 0.0f;
            var progress = UtilsMath.CalcPercent(iValue, iMaxValue);
            var progressTxt = UtilsMath.GetPercentText1(progress);
            var progressDetail = ConvertProgressDisplayTxt($"({progressTxt}):{iValue}/{iMaxValue} - {iDisplayTxt}");
            if (-1L != iCostTime)
            {
                var costTime = UtilsTime.ConvertToDisplayTime(iCostTime, false, 2);
                EditorUtility.DisplayProgressBar($"{iTitle}({costTime})", progressDetail, progress);
                return progress;
            }
            EditorUtility.DisplayProgressBar(iTitle, progressDetail, progress);
            return progress;
        }

        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iDisplayTxt">进度条内容</param>
        /// <param name="iValue">进度值</param>
        /// <param name="iMaxValue">最大值</param>
        /// <param name="iCostTime">耗时(单位:毫秒)</param>
        /// <para>百分比进度</para>
        public static float DisplayProgressBar(string iTitle, string iDisplayTxt, int iValue, int iMaxValue, long iCostTime = -1L)
        {
            if(CiMode.None != BuildParameters.CiMode) return 0.0f;
            var progress = UtilsMath.CalcPercent(iValue, iMaxValue);
            var progressTxt = UtilsMath.GetPercentText1(progress);
            var progressDetail = ConvertProgressDisplayTxt($"({progressTxt}):{iValue}/{iMaxValue} - {iDisplayTxt}");
            if (-1L != iCostTime)
            {
                var costTime = UtilsTime.ConvertToDisplayTime(iCostTime, false, 2);
                EditorUtility.DisplayProgressBar($"{iTitle}({costTime})", progressDetail, progress);
                return progress;
            }
            EditorUtility.DisplayProgressBar(iTitle, progressDetail, progress);
            return progress;
        }
        
        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iDisplayTxt">进度条内容</param>
        /// <param name="iProgress">进度</param>
        /// <param name="iCostTime">耗时(单位:毫秒)</param>
        /// <para>百分比进度</para>
        public static float DisplayProgressBar(string iTitle, string iDisplayTxt, float iProgress, long iCostTime = -1L)
        {
            if(CiMode.None != BuildParameters.CiMode) return 0.0f;
            var progressTxt = UtilsMath.GetPercentText1(iProgress);
            var progressDetail = ConvertProgressDisplayTxt($"({progressTxt}) - {iDisplayTxt}");
            if (-1L != iCostTime)
            {
                var costTime = UtilsTime.ConvertToDisplayTime(iCostTime, false, 2);
                EditorUtility.DisplayProgressBar($"{iTitle}({costTime})", progressDetail, iProgress);
                return iProgress;
            }
            EditorUtility.DisplayProgressBar(iTitle, progressDetail, iProgress);
            return iProgress;
        }

        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iDisplayTxt">进度条内容</param>
        /// <param name="iValue">进度值</param>
        /// <param name="iMaxValue">最大值</param>
        /// <param name="oCanceled">被取消标志位</param>
        /// <param name="iCostTime">耗时(单位:毫秒)</param>
        /// <para>百分比进度</para>
        /// <para>true:取消; false:未取消;</para>
        public static float DisplayCancelableProgressBar(
            string iTitle, string iDisplayTxt, int iValue, int iMaxValue, 
            out bool oCanceled, long iCostTime = -1L)
        {
            oCanceled = false;
            if(CiMode.None != BuildParameters.CiMode) return 0.0f;
            var progress = UtilsMath.CalcPercent(iValue, iMaxValue);
            var progressTxt = UtilsMath.GetPercentText1(progress);
            var progressDetail = ConvertProgressDisplayTxt($"({progressTxt}):{iValue}/{iMaxValue} - {iDisplayTxt}");
            if (-1L != iCostTime)
            {
                var costTime = UtilsTime.ConvertToDisplayTime(iCostTime, false, 2);
                oCanceled = EditorUtility.DisplayCancelableProgressBar($"{iTitle}({costTime})", progressDetail, progress);
                return progress;
            }
            
            oCanceled = EditorUtility.DisplayCancelableProgressBar(iTitle, progressDetail, progress);
            return progress;
        }
        
        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iDisplayTxt">进度条内容</param>
        /// <param name="iProgress">进度</param>
        /// <param name="iCostTime">耗时(单位:毫秒)</param>
        /// <para>true:取消; false:未取消;</para>
        public static bool DisplayCancelableProgressBar(string iTitle, string iDisplayTxt, float iProgress, long iCostTime = -1L)
        {
            if(CiMode.None != BuildParameters.CiMode) return false;
            var progressTxt = UtilsMath.GetPercentText1(iProgress);
            var progressDetail = ConvertProgressDisplayTxt($"({progressTxt}) - {iDisplayTxt}");
            if (-1L != iCostTime)
            {
                var costTime = UtilsTime.ConvertToDisplayTime(iCostTime, false, 2);
                return EditorUtility.DisplayCancelableProgressBar($"{iTitle}({costTime})", progressDetail, iProgress);
            }
            return EditorUtility.DisplayCancelableProgressBar(iTitle, progressDetail, iProgress);
        }

        private static string ConvertProgressDisplayTxt(string iDisplayTxt, int iMaxLen = 58)
        {
            if (string.IsNullOrEmpty(iDisplayTxt)) return null;
            if (iMaxLen >= iDisplayTxt.Length) return iDisplayTxt;

            var displayTxt = iDisplayTxt.Substring(0, iMaxLen);
            return $"{displayTxt}...";
        }

        /// <summary>
        /// 清空进度条弹窗
        /// </summary>
        public static void ClearProgressBar()
        {
            if(CiMode.None != BuildParameters.CiMode) return;
            EditorUtility.ClearProgressBar();
        }
        
#endregion

#region Dialog

        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iMessage">消息</param>
        /// <param name="iBtnTxt">左边按钮文本</param>
        public static void DisplayDialog(string iTitle, string iMessage, string iBtnTxt)
        {
            if(CiMode.None != BuildParameters.CiMode) return;
            EditorUtility.DisplayDialog(iTitle, iMessage, iBtnTxt);
        }

        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iMessage">消息</param>
        /// <param name="iLeftBtnTxt">左边按钮文本</param>
        /// <param name="iRightBtnTxt">右边按钮文本</param>
        /// <param name="iOnLeftBtnClicked">左侧按钮点击回调</param>
        /// <param name="iOnRightBtnClicked">右侧按钮点击回调</param>
        public static void DisplayDialog(string iTitle, string iMessage, string iLeftBtnTxt, string iRightBtnTxt,
            System.Action iOnLeftBtnClicked, System.Action iOnRightBtnClicked = null)
        {
            if (CiMode.None != BuildParameters.CiMode)
            {
                iOnLeftBtnClicked?.Invoke();
                return;
            }

            if (EditorUtility.DisplayDialog(iTitle, iMessage, iLeftBtnTxt, iRightBtnTxt))
            {
                iOnLeftBtnClicked?.Invoke();
            }
            else
            {
                iOnRightBtnClicked?.Invoke();
            }
        }

        /// <summary>
        /// 显示进度条
        /// </summary>
        /// <param name="iTitle">标题</param>
        /// <param name="iMessage">消息</param>
        /// <param name="iLeftBtnTxt">左边按钮文本</param>
        /// <param name="iMidBtnTxt">中间按钮文本</param>
        /// <param name="iRightBtnTxt">右边按钮文本</param>
        /// <param name="iOnLeftBtnClicked">左侧按钮点击回调</param>
        /// <param name="iOnMidBtnClicked">中间按钮点击回调</param>
        /// <param name="iOnRightBtnClicked">右侧按钮点击回调</param>
        public static void DisplayDialog(string iTitle, string iMessage, string iLeftBtnTxt, 
            string iMidBtnTxt, string iRightBtnTxt, System.Action iOnLeftBtnClicked, 
            System.Action iOnMidBtnClicked, System.Action iOnRightBtnClicked)
        {
            if (CiMode.None != BuildParameters.CiMode)
            {
                iOnMidBtnClicked?.Invoke();
                return;
            }
            var index = EditorUtility.DisplayDialogComplex(iTitle, iMessage, iLeftBtnTxt, iMidBtnTxt, iRightBtnTxt);
            switch (index)
            {
                case 0:
                {
                    iOnLeftBtnClicked?.Invoke();
                }
                    break;
                case 1:
                {
                    iOnMidBtnClicked?.Invoke();
                }
                    break;
                case 2:
                {
                    iOnRightBtnClicked?.Invoke();
                }
                    break;
                default:
                    break;
            }
        }

#endregion

#region PropertyField
        
		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iProperty">序列化属性</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iOnChanged">值变更回调</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawProperty(Rect iRect, Event iEvent, SerializedProperty iProperty,
			GUIContent iCaption = null, Action<SerializedProperty> iOnChanged = null, 
			int iOptions = (int)GUIOperateOptions.None)
		{
			var bgRect = iRect;
			var drawBg = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.DrawBg);
			if (drawBg)
			{
				bgRect = DrawGenericBg(iRect, iEvent, Color.clear, GuiExHelper.HeaderBackground, false, false, iOptions);
			}
			var startX = bgRect.xMin;

			var titleRect = bgRect;
			// 缩进重新绘制
			if (UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.IntentRepaint))
			{
				titleRect.xMin = SerializedPropertyType.Generic == iProperty.propertyType ? 
					startX + EditorConst.ExpandableIntent : startX + EditorConst.LabelIntent;
			}
			
			var drawNoCaption = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.MemberNoCaption);
			if (drawNoCaption)
			{
				var dirty = false;
				switch (iProperty.propertyType)
				{
					case SerializedPropertyType.String:
					{
						var valueTmp = EditorGUI.TextField(titleRect, iProperty.stringValue);
						dirty = UtilsString.Diff(valueTmp, iProperty.stringValue);
						if (dirty)
						{
							iProperty.stringValue = valueTmp;
						}
					}
						break;
					default:
						throw new UnknownPropertyProtoTypeException(iProperty.propertyType, "未处理类型，请追加处理");
				}

				if (dirty)
				{
					iOnChanged?.Invoke(iProperty);
				}
			}
			else
			{
				EditorGUI.BeginChangeCheck();
				if (null == iCaption)
				{
					EditorGUI.PropertyField(titleRect, iProperty);
				}
				else
				{
					EditorGUI.PropertyField(titleRect, iProperty, iCaption);
				}
				// 值变更回调
				if (EditorGUI.EndChangeCheck())
				{
					iOnChanged?.Invoke(iProperty);
				}
			}
			
			return bgRect;
		}

#endregion

#region Label

		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawLabel(Rect iRect, Event iEvent, GUIContent iCaption, 
			int iOptions = (int)GUIOperateOptions.DefaultLabel)
		{
			return DrawLabel(iRect, iEvent, iCaption, null, EditorStyles.label, iOptions);
		}		
		
		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iStyle">风格</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawLabel(Rect iRect, Event iEvent, GUIContent iCaption, 
			GUIStyle iStyle, int iOptions = (int)GUIOperateOptions.DefaultLabel)
		{
			return DrawLabel(iRect, iEvent, iCaption, null, iStyle, iOptions);
		}

		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iText">文本</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawLabel(Rect iRect, Event iEvent, GUIContent iCaption, 
			GUIContent iText, int iOptions = (int)GUIOperateOptions.DefaultLabel)
		{
			return DrawLabel(iRect, iEvent, iCaption, iText, EditorStyles.label, iOptions);
		}

		private static int _guiExControlIdLabel = "UtilsGUIEx_Label".GetHashCode();

		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iText">文本</param>
		/// <param name="iStyle">风格</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawLabel(Rect iRect, Event iEvent, GUIContent iCaption,
			GUIContent iText, GUIStyle iStyle, int iOptions = (int)GUIOperateOptions.DefaultLabel)
		{
			return DrawLabel(iRect, iEvent, iCaption, iText, iStyle, out var oClickableRect, iOptions);
		}
		
		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iText">文本</param>
		/// <param name="iStyle">风格</param>
		/// <param name="oClickableRect">可点击区域</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawLabel(Rect iRect, Event iEvent, GUIContent iCaption, 
			GUIContent iText, GUIStyle iStyle, out Rect oClickableRect,
			int iOptions = (int)GUIOperateOptions.DefaultLabel)
		{
			oClickableRect = Rect.zero;
			// 背景
			var bgRect = iRect;
			var drawBg = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.DrawBg);
			if (drawBg)
			{
				var draggable = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.Draggable);
				if (draggable)
				{
					bgRect = DrawDraggableBg(iRect, iEvent, false, false);
				}
				else
				{
					bgRect = DrawGenericBg(iRect, iEvent, Color.clear, GuiExHelper.HeaderBackground, false, false, iOptions);
				}
			}
			        
			// 标题区域
			var titleRect = bgRect;
			// titleRect.xMin += drawBg ? EditorConst.LabelIntent : EditorConst.HorizontalSpacing;
			// titleRect.xMax -= drawBg ? EditorConst.LabelIntent : EditorConst.HorizontalSpacing;
			        
			if (null == iText)
			{
				if (UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.Selectable))
				{
					EditorGUI.SelectableLabel(titleRect, iCaption.text, iStyle);
				}
				else
				{
					GUI.Label(titleRect, iCaption, iStyle);
				}
			}
			else
			{
				var controlId = GUIUtility.GetControlID(_guiExControlIdLabel, FocusType.Passive, titleRect);
				var labelBgRect = EditorGUI.PrefixLabel(titleRect, controlId, iCaption);

				oClickableRect = labelBgRect;
				oClickableRect.xMin += 1;
				oClickableRect.xMax -= 1;
				oClickableRect.yMin += 1;
				oClickableRect.yMax -= 1;
				
				if (Event.current.type == EventType.Repaint)
				{
					var draggable = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.Draggable);
					if (draggable)
					{
						labelBgRect = DrawDraggableBg(labelBgRect, iEvent, false, false);
					}
					
					var bgColor = GetGuiBgColor(iOptions);
					if (!ColorEx.IsSameColor(bgColor, Color.clear))
					{
						using (new BackgroundColorScope(bgColor))
						{
							GuiExHelper.HeaderBackground.Draw(oClickableRect, false, false, false, false);
						}
					}
					iStyle.Draw(oClickableRect, iText, controlId);
				}
			}

			return bgRect;
		}

#endregion

#region TextField

		/// <summary>
		/// 绘制Label
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iText">文本内容</param>
		/// <param name="iOnChanged">值变更时间</param>
		/// <param name="iOptions">操作选项</param>
		public static Rect DrawTextField(Rect iRect, Event iEvent, string iText,
			Action<string> iOnChanged, int iOptions = (int)GUIOperateOptions.None)
		{
			var displayRect = iRect;
            
			EditorGUI.BeginChangeCheck();
			var inputTxt = EditorGUI.TextField(displayRect, iText);
			if (EditorGUI.EndChangeCheck())
			{
				if (UtilsString.Diff(inputTxt, iText))
				{
					iOnChanged.Invoke(inputTxt);
				}
			}
			
			return displayRect;
		}

#endregion

#region Foldout

		/// <summary>
		/// 绘制可展开空间
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iProperty">Property</param>
		/// <param name="iCaption">标题</param>
		/// <param name="iOnChanged">展开/缩进变化回调</param>
		/// <param name="iToggleOnCaption">点击标签是否展开标志位</param>
		/// <param name="iOptions">操作选项</param>
		/// <param name="iDeltaWidth">调整用变化宽度</param>
		public static Rect DrawFoldout(Rect iRect, Event iEvent, SerializedProperty iProperty, 
			GUIContent iCaption, Action<bool> iOnChanged = null, bool iToggleOnCaption = true, 
			int iOptions = (int)GUIOperateOptions.Foldout, float iDeltaWidth = 0.0f)
		{
			if (null == iProperty) return iRect;
				
			var drawBg = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.DrawBg);
			var expandable = UtilsBytes.CheckBytes(iOptions, (int)GUIOperateOptions.Expandable);
			
			// 背景
			var bgRect = iRect;
			if (drawBg)
			{
				bgRect = DrawGenericBg(bgRect, iEvent, Color.clear, GuiExHelper.HeaderBackground, false, false, iOptions);
			}
					        
			// 标题区域
			var titleRect = bgRect;
			titleRect.xMin += expandable ? 7.0f : 3.0f;
					        
			iCaption = EditorGUI.BeginProperty(titleRect, iCaption, iProperty);
			// 可展开
			if (expandable) 
			{
				titleRect.xMin += 10;
				titleRect.xMax += iDeltaWidth;
				EditorGUI.BeginChangeCheck();
				// 绘制折叠标题
				var styleTmp = GuiExHelper.FoldoutHeader;

				styleTmp.fixedWidth = titleRect.width + 14;
				styleTmp.stretchWidth = true;
				
				var isExpanded = EditorGUI.Foldout(titleRect, iProperty.isExpanded, iCaption, iToggleOnCaption, styleTmp);
				if (EditorGUI.EndChangeCheck()) 
				{
					if (null == iOnChanged)
					{
						iProperty.isExpanded = isExpanded;
					}
					else
					{
						iOnChanged.Invoke(isExpanded);
					}
				}
			}
			else 
			{
				GUI.Label(titleRect, iCaption, EditorStyles.label);
			}

			EditorGUI.EndProperty();

			return iRect;
		}

#endregion

#region Button

		/// <summary>
		/// 绘制浏览按钮(文件/文件夹)
		/// <para>* 文件后缀列表格式:{ "FileType", "FileExtensions" }</para>
		/// <para>* 如：{ "Image files", "png,jpg,jpeg" }</para>
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iBrowsePath">浏览路径</param>
		/// <param name="iOnBrowseBtnClicked">浏览按钮点击事件</param>
		/// <param name="iIsFile">文件标识位</param>
		/// <param name="iDialogDesc">浏览对话描述</param>
		/// <param name="iExtensions">文件后缀列表(当且仅当浏览文件按钮时有效)</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawBrowseButton(Rect iRect, Event iEvent, string iBrowsePath, 
			Action<string> iOnBrowseBtnClicked, bool iIsFile = true, string iDialogDesc = null,
			string[] iExtensions = null)
		{
			var browsePath = iBrowsePath;
			if (string.IsNullOrEmpty(browsePath))
			{
				browsePath = Application.dataPath;
			}
			
			var browseDirName = UtilsIo.GetDirName(browsePath, out var oParentDir, true);

			var dialogDesc = iDialogDesc;
			if (string.IsNullOrEmpty(dialogDesc))
			{
				dialogDesc = iIsFile ? "Please select a file!" : "Please select a folder!";
			}

			var extensions = iExtensions;
			if (null == extensions || 0 >= extensions.Length)
			{
				extensions = UtilsIo.FileDefaultExtensions;
			}
			
			return DrawButton(iRect, iEvent, GuiExHelper.BrowseBtnContent,
				() =>
				{
					var browsePathTmp = iIsFile ? 
						EditorUtility.OpenFilePanelWithFilters(dialogDesc, oParentDir, extensions) : 
						EditorUtility.OpenFolderPanel(dialogDesc, oParentDir, browseDirName);
					if (!string.IsNullOrEmpty(browsePathTmp))
					{
						if (UtilsIo.IsAssetPath(browsePathTmp, out var oAssetPath))
						{
							browsePathTmp = oAssetPath;
						}
					}
					else
					{
						browsePathTmp = iBrowsePath;
					}

					iOnBrowseBtnClicked.Invoke(browsePathTmp);
				}, Color.green);
		}

		/// <summary>
		/// 绘制按钮
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">按钮标题</param>
		/// <param name="iOnBtnClicked">按钮点击事件</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawFooterButton(Rect iRect, Event iEvent, GUIContent iCaption, Action iOnBtnClicked)
		{
			return DrawFooterButton(iRect, iEvent, iCaption, iOnBtnClicked, null);
		}

		/// <summary>
		/// 绘制按钮
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">按钮标题</param>
		/// <param name="iOnBtnClicked">按钮点击事件</param>
		/// <param name="iBtStyle">按钮Style</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawFooterButton(Rect iRect, Event iEvent, GUIContent iCaption, Action iOnBtnClicked, GUIStyle iBtStyle)
		{
			return DrawButton(iRect, iEvent, iCaption, iOnBtnClicked, Color.clear, Color.clear, iBtStyle, GuiExHelper.FooterBackground);
		}

		/// <summary>
		/// 绘制按钮
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">按钮标题</param>
		/// <param name="iOnBtnClicked">按钮点击事件</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawButton(Rect iRect, Event iEvent, GUIContent iCaption, Action iOnBtnClicked)
		{
			return DrawButton(iRect, iEvent, iCaption, iOnBtnClicked, Color.clear);
		}
        
		/// <summary>
		/// 绘制按钮
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">按钮标题</param>
		/// <param name="iOnBtnClicked">按钮点击事件</param>
		/// <param name="iBtnColor">按钮景色</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawButton(Rect iRect, Event iEvent, GUIContent iCaption, Action iOnBtnClicked, Color iBtnColor)
		{
			return DrawButton(iRect, iEvent, iCaption, iOnBtnClicked, iBtnColor, null);
		}
		
		/// <summary>
		/// 绘制按钮
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">按钮标题</param>
		/// <param name="iOnBtnClicked">按钮点击事件</param>
		/// <param name="iBtnColor">按钮景色</param>
		/// <param name="iStyle">按钮Style</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawButton(Rect iRect, Event iEvent, GUIContent iCaption, Action iOnBtnClicked, Color iBtnColor, GUIStyle iStyle)
		{
			return DrawButton(iRect, iEvent, iCaption, iOnBtnClicked, iBtnColor, Color.clear, iStyle, null);
		}
		
		/// <summary>
		/// 绘制按钮
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iCaption">按钮标题</param>
		/// <param name="iOnBtnClicked">按钮点击事件</param>
		/// <param name="iBtnColor">按钮景色</param>
		/// <param name="iBgColor">背景景色</param>
		/// <param name="iStyle">按钮Style</param>
		/// <param name="iBgStyle">背景Style</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawButton(Rect iRect, Event iEvent, GUIContent iCaption, Action iOnBtnClicked, 
			Color iBtnColor, Color iBgColor, GUIStyle iStyle, GUIStyle iBgStyle)
		{
			var displayRect = iRect;

			var bgRect = displayRect;
			if (null != iBgStyle)
			{
				bgRect = DrawGenericBg(bgRect, iEvent, iBgColor, iBgStyle, false, false);
			}

			var btnRect = bgRect;
			btnRect.xMin += 1;
			btnRect.xMax -= 1;
			btnRect.yMin += 1;
			btnRect.yMax -= 1;
			if (ColorEx.IsSameColor(Color.clear, iBtnColor))
			{
				if (null == iStyle)
				{
					if (GUI.Button(btnRect, iCaption))
					{
						iOnBtnClicked?.Invoke();
					}
				}
				else
				{
					if (GUI.Button(btnRect, iCaption, iStyle))
					{
						iOnBtnClicked?.Invoke();
					}
				}
			}
			else
			{
				using (new BackgroundColorScope(iBtnColor))
				{
					if (null == iStyle)
					{
						if (GUI.Button(btnRect, iCaption))
						{
							iOnBtnClicked?.Invoke();
						}
					}
					else
					{
						if (GUI.Button(btnRect, iCaption, iStyle))
						{
							iOnBtnClicked?.Invoke();
						}
					}
				}
			}
			
			return displayRect;
		}

#endregion

#region Background

		/// <summary>
		/// 绘制列表Element背景
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iSelected">选中</param>
		/// <param name="iFocused">焦点</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawListElementBg(Rect iRect, Event iEvent, bool iSelected, bool iFocused)
		{
			return DrawGenericBg(iRect, iEvent, Color.clear, GuiExHelper.ElementBackground, iSelected, iFocused, (int)GUIOperateOptions.ListElementBg);
		}
		
		/// <summary>
		/// 绘制列表Element背景 - I/O对象背景
		/// <para>* 文件+文件夹</para>
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iSelected">选中</param>
		/// <param name="iFocused">焦点</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawIoTargetBg(Rect iRect, Event iEvent, bool iSelected, bool iFocused)
		{
			return DrawGenericBg(iRect, iEvent, Color.clear, GuiExHelper.ClickableBackground, iSelected, iFocused, (int)GUIOperateOptions.IoTargetBg);
		}
		
		/// <summary>
		/// 绘制可拖拽区域背景
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iSelected">选中</param>
		/// <param name="iFocused">焦点</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawDraggableBg(Rect iRect, Event iEvent, bool iSelected, bool iFocused)
		{
			return DrawGenericBg(iRect, iEvent, GuiExHelper.DragAreaBackground, iSelected, iFocused, (int)GUIOperateOptions.DraggableBg);
		}
        
		/// <summary>
		/// 绘制背景
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iOptions">操作选项</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawGenericBg(Rect iRect, Event iEvent, int iOptions = (int)GUIOperateOptions.DrawBg)
		{
			return DrawGenericBg(iRect, iEvent, Color.clear, iOptions);
		}
		
		/// <summary>
		/// 绘制背景
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iBgColor">背景色</param>
		/// <param name="iOptions">操作选项</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawGenericBg(Rect iRect, Event iEvent, Color iBgColor, 
			int iOptions = (int)GUIOperateOptions.DrawBg)
		{
			return DrawGenericBg(iRect, iEvent, iBgColor, GuiExHelper.HeaderBackground, false, false, iOptions);
		}

		/// <summary>
		/// 绘制背景
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iBgColor">背景色</param>
		/// <param name="iStyle">背景Style</param>
		/// <param name="iSelected">选中</param>
		/// <param name="iFocused">焦点</param>
		/// <param name="iOptions">操作选项</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawGenericBg(Rect iRect, Event iEvent, Color iBgColor, 
			GUIStyle iStyle, bool iSelected, bool iFocused, int iOptions = (int)GUIOperateOptions.DrawBg)
		{
		            
			var bgRect = iRect;
			if (iEvent.type != EventType.Repaint) return bgRect;

			var bgColor = ColorEx.IsSameColor(iBgColor, Color.clear) ? GetGuiBgColor(iOptions) : iBgColor;
			if (ColorEx.IsSameColor(Color.clear, bgColor))
			{
				iStyle.Draw(bgRect, false, iSelected, iSelected, iFocused);
			}
			else
			{
				using (new BackgroundColorScope(bgColor))
				{
					iStyle.Draw(bgRect, false, iSelected, iSelected, iFocused);
				}
			}
			return bgRect;
		}

		/// <summary>
		/// 绘制背景
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iStyle">背景Style</param>
		/// <param name="iSelected">选中</param>
		/// <param name="iFocused">焦点</param>
		/// <param name="iOptions">操作选项</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawGenericBg(Rect iRect, Event iEvent, 
			GUIStyle iStyle, bool iSelected, bool iFocused, int iOptions = (int)GUIOperateOptions.DrawBg)
		{
		            
			var bgRect = iRect;
			if (iEvent.type != EventType.Repaint) return bgRect;
			
			iStyle.Draw(bgRect, false, iSelected, iSelected, iFocused);
			return bgRect;
		}
		
#endregion

#region DargMarks

		/// <summary>
		/// 绘制拖拽Mark
		/// </summary>
		/// <param name="iRect">绘制矩形区域</param>
		/// <param name="iEvent">Event</param>
		/// <param name="iOptions">操作选项</param>
		/// <returns>绘制的矩形区域</returns>
		public static Rect DrawDragMark(Rect iRect, Event iEvent, int iOptions = (int)GUIOperateOptions.None)
		{
			var displayRect = iRect;
			if (EventType.Repaint == iEvent.type) 
			{
				GuiExHelper.DraggingHandle.Draw(new Rect(iRect.x + 5, iRect.y + 6, 10, iRect.height - (iRect.height - 6)), 
					false, false, false, false);
			}
			return displayRect;
		}

#endregion
        
#region ClipBoard

		/// <summary>
		/// 拷贝到剪切板
		/// </summary>
		/// <param name="iStr">字符串</param>
		public static void CopyToClipBoard(string iStr)
		{
			GUIUtility.systemCopyBuffer = iStr;
		}

#endregion

#region Ping

		/// <summary>
		/// 选中目标资产
		/// </summary>
		/// <param name="iAssetPath">资产路径</param>
		/// <param name="iSelectActivated">激活选中目标</param>
		/// <returns>true:Ok; false:Ng;</returns>
		public static bool PingAsset(string iAssetPath, bool iSelectActivated = false)
		{
			if(string.IsNullOrEmpty(iAssetPath)) return false;

			Object assetObj = null;
			if (Directory.Exists(iAssetPath))
			{
				assetObj = AssetDatabase.LoadAssetAtPath<Object>(iAssetPath);
			}
			else
			{
				var assetType = AssetDatabase.GetMainAssetTypeAtPath(iAssetPath);
				assetObj = AssetDatabase.LoadAssetAtPath(iAssetPath, assetType);
			}
		            
			if (null != assetObj)
			{
				EditorGUIUtility.PingObject(assetObj);
				if (iSelectActivated)
				{
					Selection.activeObject = assetObj;
				}
			}

			return true;
		}

#endregion

#region Focus

		/// <summary>
		/// 重置控件焦点
		/// </summary>
		/// <param name="iControlId">控件Id</param>
		public static void ResetControlFocus(int iControlId = 0)
		{
			GUIUtility.keyboardControl = iControlId;
		}

#endregion
        
    }
}
